﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using mepostras.BLL;
using mepostras.BO.Util;
using mepostras.DAL;
using GeneralCode = mepostras.BO.Util.BoConfig.MessageCode.General;
using Log;
namespace mepostras.BO
{
    public class MenuBo : IMenuBo
    {
        /// <summary>
        /// Render alias dựa vào title
        /// </summary>
        /// <param name="title"></param>
        /// <param name="currentAlias"></param>
        /// <returns></returns>
        private string RenderAlias(string title, string currentAlias)
        {
            var alias = BoCommon.ConvertToUnSign(title);

            // Nếu alias mới render trùng với alias hiện tại thì ko cần render nữa
            if (alias == currentAlias && !string.IsNullOrEmpty(currentAlias))
            {
                return alias;
            }

            int index = 0;

            // Lặp cho đến khi nào có alias là unique
            while (true)
            {
                if (GetByAlias(alias) == null)
                {
                    break;
                }

                index++;
                alias = BoCommon.ConvertToUnSign(String.Format("{0}-{1}", title, index));
            }

            return alias;
        }

        /// <summary>
        /// Decode để hiển thị ra Html
        /// </summary>
        /// <param name="menu"></param>
        /// <returns></returns>
        private void HtmlDecode(Menu menu)
        {
            if (menu != null)
            {
                menu.Title = HttpUtility.HtmlDecode(menu.Title);
            }
        }

        /// <summary>
        /// Encode để hiển thị ra Html
        /// </summary>
        /// <param name="menu"></param>
        /// <returns></returns>
        private void HtmlEncode(Menu menu)
        {
            if (menu != null)
            {
                menu.Title = HttpUtility.HtmlEncode(menu.Title);
            }
        }

        /// <summary>
        /// Update menu có article
        /// </summary>
        /// <param name="menu"></param>
        /// <param name="article"></param>
        /// <param name="messageCode"></param>
        /// <returns></returns>
        public bool Update(Menu menu, Article article, out string messageCode)
        {
            messageCode = GeneralCode.ServerError;
            bool result = false;
            try
            {
                menu.UpdatedDate = DateTime.Now.Date;

                // Render ra alias, link
                string alias = RenderAlias(menu.Title, menu.Alias);
                string link = String.Format("{0}/{1}", menu.MenuType.ToLower()[0], alias);

                // Dựa vào loại menu
                switch (menu.MenuType)
                {
                    case BoConfig.MenuType.Link:
                        // Trường hợp là link thì dùng link do user nhập, chỉ cập nhật alias
                        menu.Alias = alias;
                        break;
                    case BoConfig.MenuType.List:
                        // Trường hợp là link thì cập nhật alias và link ở trên
                        menu.Alias = alias;
                        menu.Link = link;
                        break;
                    case BoConfig.MenuType.Single:
                        // Set các giá trị cho article
                        article.Title = menu.Title;
                        article.MenuId = menu.Id;
                        article.IsAllowDelete = false;
                        article.Language = menu.Language;
                        if (article.PublishedDate == null)
                        {
                            article.PublishedDate = DateTime.Now;
                        }

                        // Trường hợp là single thì set title của article là title của menu
                        // Insert hoặc Update article xong thì lấy alias của article mà gán cho link của menu
                        menu.Link = BoFactory.ArticleBo.Save(article, out messageCode)
                                        ? String.Format("{0}/{1}", menu.MenuType.ToLower()[0], article.Alias)
                                        : link;

                        menu.Alias = alias;
                        break;
                }

                result = DataRepository.MenuProvider.Update(menu);
                messageCode = result ? GeneralCode.UpdateSuccess : GeneralCode.UpdateFail;
            }
            catch (Exception ex)
            {
                SingletonLogger.Instance.Error("Update", ex);
            }
            return result;
        }

        public bool Create(Menu menu, out string messageCode)
        {
            messageCode = GeneralCode.ServerError;
            bool result = false;
            try
            {
                menu.UpdatedDate = DateTime.Now.Date;
                result = DataRepository.MenuProvider.Insert(menu);
                messageCode = result ? GeneralCode.InsertSuccess : GeneralCode.InsertFail;
            }
            catch (Exception ex)
            {
                SingletonLogger.Instance.Error("Insert", ex);
            }
            return result;

        }

        public bool Update(Menu menu, out string messageCode)
        {
            messageCode = GeneralCode.ServerError;
            bool result = false;
            try
            {
                menu.UpdatedDate = DateTime.Now.Date;
                result = DataRepository.MenuProvider.Update(menu);
                messageCode = result ? GeneralCode.UpdateSuccess : GeneralCode.UpdateFail;
            }
            catch (Exception ex)
            {
                SingletonLogger.Instance.Error("Update", ex);
            }
            return result;
        }

        public bool Delete(int id, out string messageCode)
        {
            messageCode = GeneralCode.ServerError;
            bool result = false;
            try
            {

                result = DataRepository.MenuProvider.Delete(id);
                messageCode = result ? GeneralCode.DeleteSuccess : GeneralCode.DeleteFail;
            }
            catch (Exception ex)
            {
                SingletonLogger.Instance.Error("Delete", ex);
            }
            return result;
        }

        /// <summary>
        /// Lấy menu theo id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public Menu Get(int id)
        {
            return DataRepository.MenuProvider.GetById(id);
        }

        /// <summary>
        /// Lấy menu theo id kèm theo article. Dùng trong admin
        /// </summary>
        /// <param name="id"></param>
        /// <param name="article"></param>
        /// <returns></returns>
        public Menu Get(int id, out Article article)
        {
            article = null;
            var menu = DataRepository.MenuProvider.GetById(id);
            try
            {
                if (menu == null || menu.MenuType != BoConfig.MenuType.Single)
                {
                    goto StepResult;
                }

                article = BoFactory.ArticleBo.GetByMenuId(id).FirstOrDefault();
                article = article ?? new Article();
            }
            catch (Exception ex)
            {
                SingletonLogger.Instance.Error("Get", ex);
            }

            StepResult:
            return DataRepository.MenuProvider.GetById(id);
        }

        public TList<Menu> Get()
        {
            var menus = DataRepository.MenuProvider.GetAll();
            menus.Sort((m1, m2) => m1.OrderIndex.CompareTo(m2.OrderIndex));
            return DataRepository.MenuProvider.GetAll();
        }

        public TList<Menu> Get(string language)
        {
            return Get().FindAll(menu => menu.Language.Equals(language, StringComparison.OrdinalIgnoreCase));
        }

        public Menu GetByAlias(string alias)
        {
            var menu = DataRepository.MenuProvider.GetByAlias(alias);
            HtmlDecode(menu);
            return menu;
        }

        public TList<Menu> Get(string position, string language)
        {
            return Get().FindAll(menu => menu.Language.Equals(language, StringComparison.OrdinalIgnoreCase) && menu.MenuPosition == position);
        }

        public TList<Menu> GetByType(string menuType, string language)
        {
            return Get().FindAll(menu => menu.Language.Equals(language, StringComparison.OrdinalIgnoreCase) && menu.MenuType == menuType);
        }

        public TList<Menu> GetByType(string menuType)
        {
            return Get().FindAll(menu => menu.MenuType == menuType);
        }

        public TList<Menu> Get(int parentId, string language)
        {
            return Get().FindAll(menu => menu.Language.Equals(language, StringComparison.OrdinalIgnoreCase) && menu.ParentId == parentId);
        }

        public TList<Menu> GetRoot(string language)
        {
            return Get().FindAll(menu => menu.Language.Equals(language, StringComparison.OrdinalIgnoreCase) && menu.ParentId == null);
        }

        /// <summary>
        /// Lấy danh sách menu trừ menu hiện tại và các menu con của nó
        /// </summary>
        /// <returns></returns>
        public TList<Menu> GetExceptMe(int id, string language)
        {
            return
                Get().FindAll(
                    menu =>
                    menu.MenuPosition == BoConfig.MenuPosition.Main &&
                    menu.Language.Equals(language, StringComparison.OrdinalIgnoreCase) && menu.ParentId != id &&
                    menu.Id != id);
        }
    }
}
